package javaapplication2;
import java.io.*;

/**
*
* @author Ronald
*/

public class TablaClases {
	
//	******************************************
//	Atributos
//	******************************************
	
	private Clase[] clases;			// Esta variable almacenara el conjunto de clases que se 
									// encontraran definidas en el archivo de analisis 
	private String archivo;			// Esta variable guardara el nombre del archivo de analisis 
	private int numClases;			// Esta variable mantendra el numero total de clases creadas
	private int numLineas;			// En esta variable se define la cantidad total de lineas
									// que componen el archivo a cargar
	private int nivelMax;			// Indica el nivel maximo en la jerarquia de herencia

//	******************************************
//	Metodos constructores
//	******************************************
	
	// Metodo " public TablaClases( String archivo ) throws IOException "
	// *************************************************************************
	// Metodo constructor que solicita como parametro el nombre del archivo a analizar
	// y a la vez instancia los atributos que componen el tipo
	// Entradas	: "String" que indica el nomnre del archivo a analizar.
	// Salida	: ninguna
	
	public TablaClases (String archivo) throws IOException {
		this.archivo = archivo;
		this.clases = new Clase[30];
		numClases = 0;
		numLineas = 0;
		nivelMax = 0;
	}

//	******************************************
//	Metodos generales
//	******************************************
	
	// Metodo " public void iniciar() throws IOException "
	// *************************************************************************	
	// Metodo que se encarga de inicializar y rellenar el arreglo "clases" con los datos 	 
	// de las clases que se han hallado en el archivo analizado.
	// Entrada: ninguna 
	// Salida:  ninguna
	
	public void iniciar() throws IOException {
		
    	Tokenizer tokenizer = new Tokenizer(archivo);
		numLineas = tokenizer.getNumLineas();
		
    	Token linea = new Token(0 , "inicio");
    	String lineaSinDelim;
    	String[] campos;
    	Clase clase;
    	numLineas = tokenizer.getNumLineas();    	    	
    	
    	for (int i=1 ; i <= numLineas ; i++) {    	    	 
    		linea = tokenizer.getLinea(i);
    		lineaSinDelim = linea.quitarDelim();
    		campos = lineaSinDelim.split("\\s+");    	
    		
    		if (!campoIsNull(campos,0) && (campos[0].compareTo("class")==0) || (campos[0].compareTo("interface")==0)) {
    			clase = new Clase (campos[1], "public" , campos[0]);
    			clases[numClases] = clase;
    			numClases++;
    			
    			if (!campoIsNull(campos,2) && campos[2].compareTo("extends")==0) {
    				clase.setPadre(campos[3]);
    				clase.setNivel(clases[buscarClase(campos[3])].getNivel()+1);
    				clases[buscarClase(campos[3])].agregarHijo(clase.getNombre());
    				
    				if (!campoIsNull(campos,4) && campos[4].compareTo("implements")==0) {
    					clase.agregarInterfaz(campos[5]);
    				}
    			}
    			else if (!campoIsNull(campos,2) && campos[2].compareTo("implements")==0) {
    				clase.agregarInterfaz(campos[3]);
    			}
    		}
    		else if (!campoIsNull(campos,1) && (campos[1].compareTo("class")==0) || (campos[1].compareTo("interface")==0)) {
    			clase = new Clase (campos[2], campos[0] , campos[1]);
    			clases[numClases] = clase;
    			numClases++;
    			if (!campoIsNull(campos,3) && campos[3].compareTo("extends")==0) {
    				clase.setPadre(campos[4]);
    				clase.setNivel(clases[buscarClase(campos[4])].getNivel()+1);
    				clases[buscarClase(campos[4])].agregarHijo(clase.getNombre());
    				if (!campoIsNull(campos,5) && campos[5].compareTo("implements")==0) {
    					clase.agregarInterfaz(campos[6]);
    				}
    			}
    			else if (!campoIsNull(campos,3) && campos[3].compareTo("implements")==0) {
    				clase.agregarInterfaz(campos[4]);
    			}
    		}
    		   		
    	}
    	getLvlMax();    	
    }	
	
	// Metodo " public int buscarClase (String id) "
	// *************************************************************************	
	// Metodo que se encarga de buscar el nombre de un clases en el arreglo "clases", 	 
	// dando como salida la posicion en el arreglo si fue hallado o "-1" si no.
	// Entrada: "String" que representa el nombre de la clase a buscar 
	// Salida:  entero que representa la posicion en el arreglo "clases" si se ha 
	//			encontrado el nombre de la clases que se buscaba, o "-1" si no se encontro  
	
	public int buscarClase (String id) {
		for(int i=0 ; i<numClases ; i++) {
			if ((clases[i].getNombre()).compareTo(id) == 0) {
				return i;
			}
		}
		return -1;
	}
	
	public int[] interfazPadre (String interfaz) {
		int maxVio = 5;
		
		int[] implementaciones = new int[15];
		int[] violaciones = new int[maxVio]; 
		  
		int contImp = 0;
		int contVio = 0;
		
		for (int a=0 ; a<5 ; a++) {
			violaciones[a]=-1;
		}				
		
		for (int i=0 ; i<numClases ; i++) {
			if (clases[i].buscarInterfaz(interfaz) != -1) {
				implementaciones[contImp] = i;
				contImp++;
			}
		}
		
		for (int j=0 ; j<contImp ; j++) {
			
			violaciones[contVio] = implementaciones[j];
			contVio++;
			
			for (int k=0 ; k<contImp ; k++) {
								
				if(clases[implementaciones[j]].buscarHijo(clases[implementaciones[k]].getNombre()) != -1) {
					violaciones[contVio] = implementaciones[k];
					contVio++;
				}
			}
			if (violaciones[contVio-1] == implementaciones[j]) {
				violaciones[contVio-1] = -1;
				contVio--;
			}
		}
		
		System.out.println(contImp+" "+contVio);
		violaciones[maxVio-1] = contVio;
		
		return violaciones;
	}
	
	// Metodo " private boolean campoIsNull (String[] campos, int i) "
	// *************************************************************************	
	// Metodo que se encarga de comprobar si el campo de un arreglo de string es vacio
	// Entrada: arreglo tipo "String[]" en donde se hara la comprobacion y 
	// 			variable de tipo "int" que indicara el campo a comprobar
	// Salida: valor booleano, "true" si el campo es vacio, "falso" si no lo es 
	
	private boolean campoIsNull (String[] campos, int i) {
		if (i >= campos.length)
			return true;
		else
			return false;
	}

	// Metodo " private void getLvlMax ( ) "
	// *************************************************************************
	// Metodo que se encarga de obtener el valor del nivel de profundidad maximo, 
	// buscandolo entre los valores del arreglo "clases", almacenandolo en la 	 
	// variable "maxNivel" a traves del metodo "setNivelMax"
	// Entrada: ninguna
	// Salida: ninguna
	
	private void getLvlMax() {
		int lvl=0;
		for (int i=0 ; i<numClases ; i++) {
			if (lvl < clases[i].getNivel())
				lvl = clases[i].getNivel();
		}
		setNivelMax(lvl);
	}
	
//	******************************************
//	Metodos set
//	******************************************

	// Metodo " private void setNivelMax ( int lvl ) "
	// *************************************************************************
	// Metodo que se encarga de asignar un valor a la variable "nivelMax" la cual  
	// indica el nivel maximo de profundidad en la jerarquia de herencia
	// Entrada	: "int", indica el numero que se asignara a la variable "nivelMax"
	// Salida	: ninguna
	
	private void setNivelMax (int lvl) {
		nivelMax = lvl;
	}
	
//	******************************************
//	Metodos get
//	******************************************

	// Metodo " public Clase getClase ( int id ) "
	// *************************************************************************
	// Metodo que se encarga de obtener un objeto del tipo "Clase" almacenado en el 
	// arreglo "clases", en la posicion "id"
	// Entrada	: "int", indica la posicion del arreglo de donde se obtendra el objeto
	// Salida	: objeto "Clase", objeto obtenido del arreglo "clases"
	
	public Clase getClase (int id) {
		if (id < numClases) {
			return clases[id];
		}
		else {
			System.out.println("Se ha excedido el numero del indice del arreglo clase");
			Clase error = new Clase("error","error","error");
			return error;
		}			
	}
	
	// Metodo " public int getNumClases ( ) "
	// *************************************************************************
	// Metodo que se encarga de obtener el numero de clases obtenidas del archivo
	// analizado y se retorna dicho valor.
	// Entrada	: ninguna
	// Salida	: "int", indica el numero de clases almacenadas
	
	public int getNumClases() {
		return numClases;
	}
	
	// Metodo " public int getNivelMax ( ) "
	// *************************************************************************
	// Metodo que se encarga de obtener el nivel de profundidad maximo en la 
	// jerarquia de clases.
	// Entrada	: ninguna
	// Salida	: "int", que indica el nivel maximo de profundidad en la jerarquia 
	
	public int getNivelMax() {
		return nivelMax;
	}
}
